package org.streets.database.internal;

import java.lang.annotation.Annotation;
import java.util.Collection;

import javax.persistence.Entity;

import org.apache.tapestry5.ioc.services.ClassFactory;
import org.slf4j.Logger;
import org.streets.commons.util.ClassLoaderUtils;
import org.streets.context.ResourceLocator;
import org.streets.context.ResourceLocator.FetchType;
import org.streets.database.RecordHandler;
import org.streets.database.SQLNestedException;
import org.streets.database.handler.BasicHandlerManager;

/**
 * Extension to {@link BasicHandlerManager} for {@link RecordHandler}
 * generated at runtime.<br>
 * This class delegates the managing process to {@link BasicHandlerManager}.
 * 
 * @author dzb
 * 
 */
public class JPAEntityHandlerManager extends BasicHandlerManager {
	
	protected final ClassFactory classFactory;
	protected final ResourceLocator resourceLocator;
	protected ClassLoader classLoader = ClassLoaderUtils.getDefaultClassLoader();
	
	public JPAEntityHandlerManager(Logger logger, ClassFactory classFactory, ResourceLocator locator) {
		super(logger);
		this.classFactory = classFactory;
		this.resourceLocator = locator;
	}
		
	/**
	 * Build and register to {@link BasicHandlerManager} a
	 * {@link RecordHandler} based on introspection of JPA annotations on the
	 * given {@link Class}
	 * 
	 * @param <T>
	 * @param clazz
	 *            the {@link Class} for which the {@link RecordHandler} is
	 *            generated
	 */
	public <T> void registerEntity(Class<T> clazz) {

		Entity entity = clazz.getAnnotation(Entity.class);
		if (entity == null) {
			logger.warn("Class ["+clazz+"] is not Annotated with javax.persist.Entity");
			return;
		}
		try {
			register(clazz, JPAHandlerBuilderUtils.create(classFactory, clazz, logger));
		} catch (Exception e) {
			throw new SQLNestedException("Register entity class ["+clazz+"] error!", e);
		}
	}
	
	public void registerPackage(String packageName) {
	    	  	    
        Collection<Object> mappings = resourceLocator.locateResources(packageName, "class", FetchType.NAME);

        for (Object mapping : mappings) {
            try {
                Class<?> mappingClazz = classLoader.loadClass((String) mapping);
                Annotation annotation = mappingClazz.getAnnotation(Entity.class);
                if (annotation != null) {
                    registerEntity(mappingClazz);
                    logger.info("JPA Entity [" + mappingClazz + "] is registered.");
                }
            } catch (ClassNotFoundException ex) {
                throw new SQLNestedException("Register entity package "+packageName+" error!", ex);
            }
        }
	}
}
